/**
 * Copyright (C) 2009 Matteo Merli <mm@merlimat.org>
 * 
 * $Id: PxlList.java 17 2009-01-12 12:36:59Z matteo.merli $
 * $URL: http://pxl-lang.googlecode.com/svn/trunk/src/main/java/pxl/types/PxlList.java $
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *         http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package pxl.types;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import pxl.errors.IndexError;
import pxl.errors.TypeError;
import pxl.errors.UnsupportedOperand;
import pxl.types.annotations.Exported;

import com.google.common.base.Join;
import com.google.common.collect.Lists;

public class PxlList extends PxlObject
{
    private final List<PxlObject> list;

    public PxlList()
    {
        list = Lists.newArrayList();
    }

    public PxlList( int size )
    {
        list = Lists.newArrayListWithExpectedSize( size );
    }

    public PxlList( Iterable<? extends PxlObject> collection )
    {
        this.list = Lists.newArrayList( collection );
    }

    @Override
    public String getType()
    {
        return "List";
    }

    @Override
    public String toString()
    {
        StringBuilder sb = new StringBuilder();
        sb.append( '[' );
        Join.join( sb, ", ", list );
        sb.append( ']' );
        return sb.toString();
    }

    protected List<PxlObject> getValue()
    {
        return list;
    }

    // // Operators

    @Exported
    @Override
    public PxlString __repr__()
    {
        return new PxlString( toString() );
    }

    @Exported
    @Override
    public PxlString __str__()
    {
        return __repr__();
    }

    @Exported
    @Override
    public PxlObject __add__( PxlObject other )
    {
        if ( other instanceof PxlList )
        {
            // Concatenate the 2 lists
            PxlList newList = new PxlList( list.size()
                    + ((PxlList) other).list.size() );

            newList.list.addAll( list );
            newList.list.addAll( ((PxlList) other).list );

            return newList;
        }

        throw new UnsupportedOperand( "+", this, other );
    }

    @Exported
    @Override
    public PxlObject __mul__( PxlObject other )
    {
        if ( other instanceof PxlInteger )
        {
            int n = (int) ((PxlInteger) other).getValue();
            // Concatenate the list  n times
            PxlList newList = new PxlList( list.size() * n );
            for ( int i = 0; i < n; i++ )
                newList.list.addAll( list );

            return newList;
        }

        throw new UnsupportedOperand( "*", this, other );
    }

    @Exported
    @Override
    public PxlBoolean __bool__()
    {
        return PxlBoolean.valueOf( list.isEmpty() );
    }

    @Exported
    @Override
    public PxlObject __getitem__( PxlObject key )
    {
        if ( !(key instanceof PxlInteger) )
            throw new TypeError( "list indices must be integers" );

        int idx = (int) ((PxlInteger) key).getValue();
        if ( idx >= list.size() )
            throw new IndexError( "list index out of range" );

        return list.get( idx );
    }

    @Exported
    @Override
    public void __setitem__( PxlObject key, PxlObject value )
    {
        if ( !(key instanceof PxlInteger) )
            throw new TypeError( "list indices  must be integers" );

        int idx = (int) ((PxlInteger) key).getValue();
        if ( idx >= list.size() )
            throw new IndexError( "list assignment index out of range" );

        list.set( idx, value );
    }

    @Exported
    @Override
    public PxlIterator __getiterator__()
    {
        return new PxlBaseIterator( list.listIterator() );
    }

    @Exported
    @Override
    public PxlInteger __len__()
    {
        return new PxlInteger( list.size() );
    }

    // "Public" methods

    @Exported
    public void add( PxlObject obj )
    {
        list.add( obj );
    }

    @Exported
    public PxlObject get( PxlObject idx )
    {
        if ( !(idx instanceof PxlInteger) )
            throw new TypeError( "list indices  must be integers" );

        int i = (int) ((PxlInteger) idx).getValue();
        return list.get( i );
    }

    @Exported
    public void sort()
    {
        // TODO
        // Collections.sort( list );
    }

    @Exported
    public void reverse()
    {
        Collections.reverse( list );
    }

    // Attributes

    private static final Map<String, PxlObject> attrs = PxlObject
            .getExportedMethods( PxlList.class );

    @Override
    protected PxlObject getAttribute( String name )
    {
        return attrs.get( name );
    }

    @Override
    protected Collection<String> getAttributeNames()
    {
        return attrs.keySet();
    }

}
